//
// Created by TongHua on 2020/12/24.
//

#ifndef WEBSERVER_HTTPCONN_H
#define WEBSERVER_HTTPCONN_H

#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/epoll.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
#include <sys/stat.h>
#include <string.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <stdarg.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/uio.h>
#include "../SQL/sql_connection_pool.hpp"
#include "../Lock/Locker.hpp"
#include "../ThreadPool/ThreadPool.h"

class HttpConn {
public:
    static const int FILENAME_LEN = 200;
    static const int READ_BUFFER_SIZE = 2048;
    static const int WRITE_BUFFER_SIZE = 1024;
    enum METHOD
    {
        GET = 0,
        POST,
        HEAD,
        PUT,
        DELETE,
        TRACE,
        OPTIONS,
        CONNECT,
        PATH
    };
    enum CHECK_STATE
    {
        CHECK_STATE_REQUESTLINE = 0,
        CHECK_STATE_HEADER = 1,
        CHECK_STATE_CONTENT = 2
    };
    enum HTTP_CODE
    {
        NO_REQUEST,
        GET_REQUEST,
        BAD_REQUEST,
        NO_RESOURCE,
        FORBIDDEN_REQUEST,
        FILE_REQUEST,
        INTERNAL_ERROR,
        CLOSED_CONNECTION
    };
    enum LINE_STATUS
    {
        LINE_OK = 0,
        LINE_BAD,
        LINE_OPEN
    };
public:
    HttpConn() {}
    ~HttpConn() {}

public:
    /***
     * 初始化
     * @param _sockfd
     * @param _address
     */
    void Init(int _sockfd,const sockaddr_in &_address);
    /***
     * 关闭http连接
     * @param _real_close
     */
    void CloseConnect(bool _real_close = true);
    /***
     * 处理函数
     */
    void Process();

    bool ReadOnce();

    bool Write();

    sockaddr_in* GetAddress() { return &m_address; }

    /**
     * 初始化SQL数据
     * @param _connPool
     */
    void InitMySQLResult( ConnectionPool* _connPool );

private:
    void Init();
    HTTP_CODE ProcessRead();
    bool ProcessWrite(HTTP_CODE _ret);
    HTTP_CODE ParseRequestLine(char* _text);
    HTTP_CODE ParseHeaders(char* _text);
    HTTP_CODE ParseContent(char* _text);
    HTTP_CODE DoRequest();
    char* GetLine() { return m_read_buf + m_start_line; }
    LINE_STATUS ParseLine();
    void Unmap();
    bool AddResponse(const char* _format,...);
    bool AddContent(const char* _content);
    bool AddStatusLine(int _status,const char* _title);
    bool AddHeaders(int _content_length);
    bool AddContentLenght(int _content_length);
    bool AddLinger();
    bool AddBlankLine();
public:
    static int m_epollfd;
    static int m_user_count;
    MYSQL* mysql;
private:
    int m_sockfd;
    sockaddr_in m_address;
    char m_read_buf[READ_BUFFER_SIZE];
    int m_read_idx;
    char m_write_buf[WRITE_BUFFER_SIZE];
    int m_write_idx;
    CHECK_STATE m_check_state;
    int m_checked_idx;
    int m_start_line;
    METHOD m_medtod;
    char m_real_file[FILENAME_LEN];
    char* m_url;
    char* m_version;
    char* m_host;
    int m_content_length;
    bool m_linger;
    char* m_file_address;
    struct stat m_file_stat;
    struct iovec m_iv[2];
    int m_iv_count;
    char* m_string;
    int m_cgi;
    Locker m_lock;
};


#endif //WEBSERVER_HTTPCONN_H
